package test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Properties;

import measures.Measures;
import model.Category;
import model.Document;
import model.Neighbour;
import utilities.DCUtilities;
import utilities.Logger;
import classification.Classificator;
import classification.DocClassification;
import classification.TestSetReader;
import features.FeaturesReduction;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		readSettings();
		try {
			Logger.addOutput(DCUtilities.STATISTICS_OUTPUT_FILE_KEY, DCUtilities.STATISTICS_OUTPUT_FILE);
		} catch (IOException e) {
			System.out.println("ERROR while opening statistics file");
		}
		
		try {
			Logger.addOutput(DCUtilities.CLASSIFICATION_OUTPUT_FILE_KEY, DCUtilities.CLASSIFICATION_OUTPUT_FILE);
		} catch (IOException e) {
			System.out.println("ERROR while opening classification output file");
		}
		
		Long time = System.currentTimeMillis();
		FeaturesReduction fr = new FeaturesReduction();
		try {
			fr.trainingClsf(DCUtilities.CORPUS_PATH);
			
			TestSetReader testReader = new TestSetReader(fr.getTerms(), fr.getCategories());
			testReader.read(DCUtilities.TEST_SET_PATH);
			List<Document> testDocuments = testReader.getDocuments();
			
			DocClassification dc = new DocClassification(fr.getDocuments(), fr.getTerms());
			long totalMissed = 0;
			long totalHits = 0;
			for (Document testDoc:testDocuments){
				List<Neighbour> neighbours = dc.getNearesNeighbours(testDoc, DCUtilities.NEARES_NEIGHBOURS_COUNT);
				
				Classificator.assignClass(testDoc, neighbours);
				
				testDoc.printDocumentCategories();
				
				totalMissed += testDoc.getMissCount();
				totalHits += testDoc.getHitCount();
			}
			
			Logger.logln("CALCULATING MEASURES");
			
			Measures measures = new Measures(testDocuments);
			measures.measure();
			measures.printStatistics();
			
			Logger.logln("TOTAL MISSED:\t"+totalMissed, DCUtilities.STATISTICS_OUTPUT_FILE_KEY);
			Logger.logln("TOTAL HITS:\t"+totalHits, DCUtilities.STATISTICS_OUTPUT_FILE_KEY);
			
			Logger.logln("TOTAL DOCUMENTS in test set:\t"+testDocuments.size(), DCUtilities.STATISTICS_OUTPUT_FILE_KEY);
			
			Logger.logln("TOTAL DOCUMENTS in training set:\t"+fr.getDocuments().size(), DCUtilities.STATISTICS_OUTPUT_FILE_KEY);
			
			time = System.currentTimeMillis() - time;
			Logger.logln("Test is finished. Test time: "+((double)time/1000.0));
		} catch (Throwable e) {
			System.out.println("[ERROR] Stemming error!");
			e.printStackTrace();
		}
		
		try {
			Logger.closeOutput(DCUtilities.STATISTICS_OUTPUT_FILE_KEY);
		} catch (IOException e) {
			System.out.println("ERROR while closing statistics file");
		}
		
		try {
			Logger.closeOutput(DCUtilities.CLASSIFICATION_OUTPUT_FILE_KEY);
		} catch (IOException e) {
			System.out.println("ERROR while closing classification output file");
		}
		System.out.println("Exiting program");
	}
	
//	private static long calculateMissed(Document first, Document second){
//		long missed = 0;
//		for (Category c:first.getCategories().values()){
//			if (!second.getCategories().containsKey(c.getCategoryName())){
//				missed++;
//			}
//		}
//		for (Category c:second.getCategories().values()){
//			if (!first.getCategories().containsKey(c.getCategoryName())){
//				missed++;
//			}
//		}
//		return missed;
//	}
//
//	private static long calculateHits(Document first, Document second){
//		long hits = 0;
//		for (Category c:first.getCategories().values()){
//			if (second.getCategories().containsKey(c.getCategoryName())){
//				hits++;
//			}
//		}
//		return hits;
//	}
	
	private static void saveSettings(){
		Properties props = new Properties();
		
		props.put("PRINT_INFO_ON_SCREEN", new Boolean(DCUtilities.PRINT_INFO_ON_SCREEN).toString());
		props.put("PRINT_LOGGED_INFO_ON_SCREEN", new Boolean(DCUtilities.PRINT_LOGGED_INFO_ON_SCREEN).toString());
		props.put("STATISTICS_OUTPUT_FILE", DCUtilities.STATISTICS_OUTPUT_FILE);
		props.put("CLASSIFICATION_OUTPUT_FILE", DCUtilities.CLASSIFICATION_OUTPUT_FILE);
		props.put("CORPUS_PATH", DCUtilities.CORPUS_PATH);
		props.put("TEST_SET_PATH", DCUtilities.TEST_SET_PATH);
		props.put("CATEGORIES_TAG", DCUtilities.CATEGORIES_TAG);
		props.put("READ_NO_TITLE", new Boolean(DCUtilities.READ_NO_TITLE).toString());
		props.put("HIGH_TF_REDUCTION_PERCENTAGE", new Double(DCUtilities.HIGH_TF_REDUCTION_PERCENTAGE).toString());
		props.put("LOW_TF_REDUCTION_PERCENTAGE", new Double(DCUtilities.LOW_TF_REDUCTION_PERCENTAGE).toString());
		props.put("REDUCTION_TRESHOLD", new Integer(DCUtilities.REDUCTION_TRESHOLD).toString());
		props.put("TITLE_BODY_DISTANCE_CHANGER", new Double(DCUtilities.TITLE_BODY_DISTANCE_CHANGER).toString());
		props.put("TITLE_TITLE_DISTANCE_CHANGER", new Double(DCUtilities.TITLE_TITLE_DISTANCE_CHANGER).toString());
		props.put("NEARES_NEIGHBOURS_COUNT", new Integer(DCUtilities.NEARES_NEIGHBOURS_COUNT).toString());
		try {
			OutputStream out = new FileOutputStream(new File("settings.txt"));
			props.store(out, "");
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	private static void readSettings(){
		Properties props = new Properties();
		try {
			InputStream in = new FileInputStream(new File("settings.txt"));
			props.load(in);
			
			DCUtilities.PRINT_INFO_ON_SCREEN = Boolean.parseBoolean(props.get("PRINT_INFO_ON_SCREEN").toString());
			
			DCUtilities.PRINT_LOGGED_INFO_ON_SCREEN = Boolean.parseBoolean(props.get("PRINT_LOGGED_INFO_ON_SCREEN").toString());
			
			DCUtilities.STATISTICS_OUTPUT_FILE = props.get("STATISTICS_OUTPUT_FILE").toString();
			
			DCUtilities.CLASSIFICATION_OUTPUT_FILE = props.get("CLASSIFICATION_OUTPUT_FILE").toString();
			
			DCUtilities.CORPUS_PATH = props.get("TRAIN_SET_PATH").toString();
			
			DCUtilities.TEST_SET_PATH = props.get("TEST_SET_PATH").toString();
			
			DCUtilities.CATEGORIES_TAG = props.get("CATEGORIES_TAG").toString();
			
			DCUtilities.READ_NO_TITLE = Boolean.parseBoolean(props.get("READ_NO_TITLE").toString());
			
			DCUtilities.HIGH_TF_REDUCTION_PERCENTAGE = Double.parseDouble(props.get("HIGH_DF_REDUCTION_PERCENTAGE").toString());
			
			DCUtilities.LOW_TF_REDUCTION_PERCENTAGE = Double.parseDouble(props.get("LOW_DF_REDUCTION_PERCENTAGE").toString());
			
			DCUtilities.REDUCTION_TRESHOLD = Integer.parseInt(props.get("REDUCTION_TRESHOLD").toString());
			
			DCUtilities.TITLE_BODY_DISTANCE_CHANGER = Double.parseDouble(props.get("TITLE_BODY_DISTANCE_CHANGER").toString());
			
			DCUtilities.TITLE_TITLE_DISTANCE_CHANGER = Double.parseDouble(props.get("TITLE_TITLE_DISTANCE_CHANGER").toString());
			
			DCUtilities.NEARES_NEIGHBOURS_COUNT = Integer.parseInt(props.get("NEARES_NEIGHBOURS_COUNT").toString());
			
			
		} catch (IOException e) {
			System.out.println("Cannot read properties - assuming default values");
		}
		
	}
	
	
}
